home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Browsers, Managers & Extensions / Mozilla Weave 0.2.7 / latest-weave.xpi / modules / engines / history.js < prev    next >
Text File  |  2008-08-08  |  9KB  |  300 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Bookmarks Sync.
  15.  *
  16.  * The Initial Developer of the Original Code is Mozilla.
  17.  * Portions created by the Initial Developer are Copyright (C) 2008
  18.  * the Initial Developer. All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *  Dan Mills <thunder@mozilla.com>
  22.  *
  23.  * Alternatively, the contents of this file may be used under the terms of
  24.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  25.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26.  * in which case the provisions of the GPL or the LGPL are applicable instead
  27.  * of those above. If you wish to allow use of your version of this file only
  28.  * under the terms of either the GPL or the LGPL, and not to allow others to
  29.  * use your version of this file under the terms of the MPL, indicate your
  30.  * decision by deleting the provisions above and replace them with the notice
  31.  * and other provisions required by the GPL or the LGPL. If you do not delete
  32.  * the provisions above, a recipient may use your version of this file under
  33.  * the terms of any one of the MPL, the GPL or the LGPL.
  34.  *
  35.  * ***** END LICENSE BLOCK ***** */
  36.  
  37. const EXPORTED_SYMBOLS = ['HistoryEngine'];
  38.  
  39. const Cc = Components.classes;
  40. const Ci = Components.interfaces;
  41. const Cu = Components.utils;
  42.  
  43. Cu.import("resource://weave/log4moz.js");
  44. Cu.import("resource://weave/util.js");
  45. Cu.import("resource://weave/engines.js");
  46. Cu.import("resource://weave/syncCores.js");
  47. Cu.import("resource://weave/stores.js");
  48. Cu.import("resource://weave/trackers.js");
  49. Cu.import("resource://weave/async.js");
  50.  
  51. Function.prototype.async = Async.sugar;
  52.  
  53. function HistoryEngine(pbeId) {
  54.   this._init(pbeId);
  55. }
  56. HistoryEngine.prototype = {
  57.   __proto__: new SyncEngine(),
  58.  
  59.   get name() { return "history"; },
  60.   get displayName() { return "Browsing History"; },
  61.   get logName() { return "HistEngine"; },
  62.   get serverPrefix() { return "user-data/history/"; },
  63.  
  64.   __store: null,
  65.   get _store() {
  66.     if (!this.__store)
  67.       this.__store = new HistoryStore();
  68.     return this.__store;
  69.   },
  70.  
  71.   __core: null,
  72.   get _core() {
  73.     if (!this.__core)
  74.       this.__core = new HistorySyncCore(this._store);
  75.     return this.__core;
  76.   },
  77.  
  78.   __tracker: null,
  79.   get _tracker() {
  80.     if (!this.__tracker)
  81.       this.__tracker = new HistoryTracker();
  82.     return this.__tracker;
  83.   }
  84. };
  85.  
  86. function HistorySyncCore(store) {
  87.   this._store = store;
  88.   this._init();
  89. }
  90. HistorySyncCore.prototype = {
  91.   _logName: "HistSync",
  92.   _store: null,
  93.  
  94.   _commandLike: function HSC_commandLike(a, b) {
  95.     // History commands never qualify for likeness.  We will always
  96.     // take the union of all client/server items.  We use the URL as
  97.     // the GUID, so the same sites will map to the same item (same
  98.     // GUID), without our intervention.
  99.     return false;
  100.   },
  101.  
  102.   /**
  103.    * Determine the differences between two snapshots.  This method overrides
  104.    * the one in its superclass so it can ignore removes, since removes don't
  105.    * matter for history (and would cause deltas to grow too large too fast).
  106.    */
  107.   _detectUpdates: function HSC__detectUpdates(a, b) {
  108.     let self = yield;
  109.  
  110.     this.__proto__.__proto__._detectUpdates.async(this, self.cb, a, b);
  111.     let cmds = yield;
  112.     cmds = cmds.filter(function (v) v.action != "remove");
  113.  
  114.     self.done(cmds);
  115.   }
  116. };
  117. HistorySyncCore.prototype.__proto__ = new SyncCore();
  118.  
  119. function HistoryStore() {
  120.   this._init();
  121. }
  122. HistoryStore.prototype = {
  123.   _logName: "HistStore",
  124.   _lookup: null,
  125.  
  126.   __hsvc: null,
  127.   get _hsvc() {
  128.     if (!this.__hsvc) {
  129.       this.__hsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
  130.                     getService(Ci.nsINavHistoryService);
  131.       this.__hsvc.QueryInterface(Ci.nsIGlobalHistory2);
  132.       this.__hsvc.QueryInterface(Ci.nsIBrowserHistory);
  133.     }
  134.     return this.__hsvc;
  135.   },
  136.  
  137.   __histDB: null,
  138.   get _histDB() {
  139.     if (!this.__histDB) {
  140.       let file = Cc["@mozilla.org/file/directory_service;1"].
  141.                  getService(Ci.nsIProperties).
  142.                  get("ProfD", Ci.nsIFile);
  143.       file.append("places.sqlite");
  144.       let stor = Cc["@mozilla.org/storage/service;1"].
  145.                  getService(Ci.mozIStorageService);
  146.       this.__histDB = stor.openDatabase(file);
  147.     }
  148.     return this.__histDB;
  149.   },
  150.  
  151.   _itemExists: function HistStore__itemExists(GUID) {
  152.     // we don't care about already-existing items; just try to re-add them
  153.     return false;
  154.   },
  155.  
  156.   _createCommand: function HistStore__createCommand(command) {
  157.     this._log.debug("  -> creating history entry: " + command.GUID);
  158.     try {
  159.       let uri = Utils.makeURI(command.data.URI);
  160.       let redirect = false;
  161.       if (command.data.transition == 5 || command.data.transition == 6)
  162.         redirect = true;
  163.  
  164.       this._hsvc.addVisit(uri, command.data.time, null,
  165.                           command.data.transition, redirect, 0);
  166.       this._hsvc.setPageTitle(uri, command.data.title);
  167.     } catch (e) {
  168.       this._log.error("Exception caught: " + (e.message? e.message : e));
  169.     }
  170.   },
  171.  
  172.   _removeCommand: function HistStore__removeCommand(command) {
  173.     this._log.trace("  -> NOT removing history entry: " + command.GUID);
  174.     // we can't remove because we only sync the last 1000 items, not
  175.     // the whole store.  So we don't know if remove commands were
  176.     // generated due to the user removing an entry or because it
  177.     // dropped past the 1000 item mark.
  178.   },
  179.  
  180.   _editCommand: function HistStore__editCommand(command) {
  181.     this._log.trace("  -> FIXME: NOT editing history entry: " + command.GUID);
  182.     // FIXME: implement!
  183.   },
  184.  
  185.   _historyRoot: function HistStore__historyRoot() {
  186.     let query = this._hsvc.getNewQuery(),
  187.         options = this._hsvc.getNewQueryOptions();
  188.  
  189.     query.minVisits = 1;
  190.     options.maxResults = 1000;
  191.     options.resultType = options.RESULTS_AS_VISIT; // FULL_VISIT does not work
  192.     options.sortingMode = options.SORT_BY_DATE_DESCENDING;
  193.     options.queryType = options.QUERY_TYPE_HISTORY;
  194.  
  195.     let root = this._hsvc.executeQuery(query, options).root;
  196.     root.QueryInterface(Ci.nsINavHistoryQueryResultNode);
  197.     return root;
  198.   },
  199.  
  200.   /* UGLY, UGLY way of syncing visit type !
  201.      We'll just have to wait for bug #320831 */
  202.   _getVisitType: function HistStore__getVisitType(uri) {
  203.     let visitStmnt = this._histDB.createStatement("SELECT visit_type FROM moz_historyvisits WHERE place_id = ?1");
  204.     let pidStmnt = this._histDB.createStatement("SELECT id FROM moz_places WHERE url = ?1");
  205.     
  206.     pidStmnt.bindUTF8StringParameter(0, uri);
  207.     
  208.     let placeID = null;
  209.     if (pidStmnt.executeStep()) {
  210.       placeID = pidStmnt.getInt32(0);
  211.     }
  212.  
  213.     if (placeID) {
  214.       visitStmnt.bindInt32Parameter(0, placeID);
  215.       if (visitStmnt.executeStep())
  216.         return visitStmnt.getInt32(0);
  217.     }
  218.     return null;
  219.   },
  220.   
  221.   wrap: function HistStore_wrap() {
  222.     let root = this._historyRoot();
  223.     root.containerOpen = true;
  224.     let items = {};
  225.     for (let i = 0; i < root.childCount; i++) {
  226.       let item = root.getChild(i);
  227.       let guid = item.time + ":" + item.uri;
  228.       let vType = this._getVisitType(item.uri);
  229.       items[guid] = {parentGUID: '',
  230.              title: item.title,
  231.              URI: item.uri,
  232.              time: item.time,
  233.              transition: vType
  234.             };
  235.     }
  236.     
  237.     this._lookup = items;
  238.     return items;
  239.   },
  240.  
  241.   wipe: function HistStore_wipe() {
  242.     this._hsvc.removeAllPages();
  243.   },
  244.  
  245.   _resetGUIDs: function FormStore__resetGUIDs() {
  246.     let self = yield;
  247.     // Not needed.
  248.   }
  249. };
  250. HistoryStore.prototype.__proto__ = new Store();
  251.  
  252. function HistoryTracker() {
  253.   this._init();
  254. }
  255. HistoryTracker.prototype = {
  256.   _logName: "HistoryTracker",
  257.  
  258.   /* We don't care about the first four */
  259.   onBeginUpdateBatch: function HT_onBeginUpdateBatch() {
  260.  
  261.   },
  262.   onEndUpdateBatch: function HT_onEndUpdateBatch() {
  263.  
  264.   },
  265.   onPageChanged: function HT_onPageChanged() {
  266.  
  267.   },
  268.   onTitleChanged: function HT_onTitleChanged() {
  269.  
  270.   },
  271.  
  272.   /* Every add or remove is worth 1 point.
  273.    * Clearing the whole history is worth 50 points,
  274.    * to ensure we're above the cutoff for syncing
  275.    * ASAP.
  276.    */
  277.   onVisit: function HT_onVisit(uri, vid, time, session, referrer, trans) {
  278.     this._score += 1;
  279.   },
  280.   onPageExpired: function HT_onPageExpired(uri, time, entry) {
  281.     this._score += 1;
  282.   },
  283.   onDeleteURI: function HT_onDeleteURI(uri) {
  284.     this._score += 1;
  285.   },
  286.   onClearHistory: function HT_onClearHistory() {
  287.     this._score += 50;
  288.   },
  289.  
  290.   _init: function HT__init() {
  291.     this._log = Log4Moz.Service.getLogger("Service." + this._logName);
  292.     this._score = 0;
  293.  
  294.     Cc["@mozilla.org/browser/nav-history-service;1"].
  295.     getService(Ci.nsINavHistoryService).
  296.     addObserver(this, false);
  297.   }
  298. }
  299. HistoryTracker.prototype.__proto__ = new Tracker();
  300.